﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Zatify.WebUI.Infrastructure;
using Zatify.Domain.Abstract;
using Zatify.WebUI.Models;
using Zatify.Domain.Data;
using Zatify.Domain.Helpers;

namespace Zatify.WebUI.Controllers
{
    using Zatify.Domain.Entities.Extensions;

    [Authorize]
    public class PromotionsController : BaseController
    {
        private IZatifyRepository repository;
        public PromotionsController(IZatifyRepository repository)
        {
            this.repository = repository;
        }

        public ActionResult Details(int id)
        {
            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value, id);

            if (id <= 0 || promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            var feets = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "feet").OrderBy(p => p.ProximityRadiusId).ToList();
            var miles = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "miles").OrderBy(p => p.ProximityRadiusId).ToList();

            var model = new PromotionDetailsViewModel();

            model.Promotion = promotion;

            var isFeetsSelected = feets.Select(x => x.ProximityRadiusId).Contains(promotion.ProximityRadiusId.Value);
            var isCutomRangeSelected = (promotion.ProximityRadiusId == repository.ProximityRadiuses.FirstOrDefault(x => x.IsCustomRate).ProximityRadiusId);
            var isOver200MilesSelected = (promotion.ProximityRadius.FromRadius == 200);

            model.SelectedRadiusText = String.Format("{1} {0}", (isFeetsSelected ? "feets" : "miles"),
                    (isFeetsSelected ? feets.FirstOrDefault(x => x.ProximityRadiusId == promotion.ProximityRadiusId).ToRadius.ToString() :
                    (isCutomRangeSelected ? promotion.CustomRange.Value.ToString() :
                    (isOver200MilesSelected ? "Over 200" : miles.FirstOrDefault(x => x.ProximityRadiusId == promotion.ProximityRadiusId).ToRadius.ToString()))));

            model.SelectedTimingText = String.Format("{0}",
                    (promotion.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW ? "Instant now" :
                    (promotion.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT ? "Scheduled at " + promotion.BaseCostTimingScheduledAt.Value.ToString("MM/dd/yy hh:mm tt") :
                    promotion.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE ?
                    String.Format("Date range with time interval from {0} to {1}; {2} - {3}",
                                    promotion.BaseCostTimingStarts.Value.ToString("MM/dd/yy"),
                                    promotion.BaseCostTimingEnds.Value.ToString("MM/dd/yy"),
                                    promotion.BaseCostTimingStarts.Value.ToString("hh:mm tt"),
                                    promotion.BaseCostTimingEnds.Value.ToString("hh:mm tt")) : String.Empty)));

            return View(model);
        }

        public ActionResult Stop(int id)
        {
            if (id > 0)
            {
                var result = this.repository.Promotion_Stop(User.SecurityToken.Value, id);
            }

            return RedirectToAction("Promotions", "BusinessProfile");
        }

        public ActionResult Delete(int id)
        {
            if (id > 0)
            {
                var result = this.repository.PromotionDeleteByBusinessTokenAndId(User.SecurityToken.Value, id);
            }

            return RedirectToAction("Promotions", "BusinessProfile");
        }

        [HttpGet]
        public ActionResult AddTime(int id)
        {
            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value, id);

            if (id <= 0 || promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            var baseCostsTiming = this.repository.BaseCostTimings.ToList();

            return View(new PromotionAddTimeViewModel()
            {
                PromotionId = id,
                BaseCostTimingId = promotion.BaseCostTimingId ?? 0,//PromotionConstants.TIMING_INSTANT_NOW,
                PromotionCompaignFlatFee = GetPromotionCompaignFixedCost(promotion),
                PromotionCompaignCost = GetPromotionCompaignPerPush(promotion),

                BaseCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush,
                InstantNowCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW).FirstOrDefault().RatePerPush,
                InstantNowFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW).FirstOrDefault().FixedCost,
                ScheduledAtCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT).FirstOrDefault().RatePerPush,
                ScheduledAtFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT).FirstOrDefault().FixedCost,
                DateRangeWithTimeIntervalCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE).FirstOrDefault().RatePerPush,
                DateRangeWithTimeIntervalFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE).FirstOrDefault().FixedCost,

                TimingFlatFee = baseCostsTiming.SingleOrDefault(x => x.BaseCostTimingId == promotion.BaseCostTimingId).FixedCost,
                TimingCost = baseCostsTiming.SingleOrDefault(x => x.BaseCostTimingId == promotion.BaseCostTimingId).RatePerPush,

                BaseCostTimingScheduledAtDate = promotion.BaseCostTimingScheduledAt ?? null,
                BaseCostTimingScheduledAtTime = promotion.BaseCostTimingScheduledAt.HasValue ? promotion.BaseCostTimingScheduledAt.Value.TimeOfDay : new Nullable<TimeSpan>(),
                BaseCostTimingStartsDate = promotion.BaseCostTimingStarts ?? null,
                BaseCostTimingStartsTime = promotion.BaseCostTimingStarts.HasValue ? promotion.BaseCostTimingStarts.Value.TimeOfDay : new Nullable<TimeSpan>(),
                BaseCostTimingEndsDate = promotion.BaseCostTimingEnds ?? null,
                BaseCostTimingEndsTime = promotion.BaseCostTimingEnds.HasValue ? promotion.BaseCostTimingEnds.Value.TimeOfDay : new Nullable<TimeSpan>(),

                RemainingBudget = promotion.UnusedMoney ?? 0,
                RemainingPushes = promotion.UnusedPushes ?? 0
            });
        }

        [HttpPost]
        public ActionResult AddTime(PromotionAddTimeViewModel model)
        {
            if (ModelState.IsValid)
            {
                var business = repository.BusinessGetByToken(User.SecurityToken.Value);

                if (model.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT)
                {
                    if (!model.BaseCostTimingScheduledAtDate.HasValue)
                    {
                        ModelState.AddModelError("BaseCostTimingScheduledAt_EmptyDate", "Select 'Scheduled at' date");
                        return View(model);
                    }
                    else
                    {
                        model.BaseCostTimingScheduledAtDate = new DateTime(
                                                   model.BaseCostTimingScheduledAtDate.Value.Year, model.BaseCostTimingScheduledAtDate.Value.Month, model.BaseCostTimingScheduledAtDate.Value.Day,
                                                   model.BaseCostTimingScheduledAtTime.Value.Hours, model.BaseCostTimingScheduledAtTime.Value.Minutes, model.BaseCostTimingScheduledAtTime.Value.Seconds);
                    }
                }
                else if (model.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE)
                {
                    if (!model.BaseCostTimingStartsDate.HasValue || !model.BaseCostTimingEndsDate.HasValue)
                    {
                        ModelState.AddModelError("BaseCostTimingStartsEndsDates_Empty", "Select 'Start Date' and 'End Date' intervals");
                    }
                    else if (model.BaseCostTimingStartsDate.Value > model.BaseCostTimingEndsDate.Value)
                    {
                        ModelState.AddModelError("BaseCostTimingStartsEndsDates_EndsDateGreater", "'End Date' must be greater than 'Start Date'");
                    }
                    else if (!model.BaseCostTimingStartsTime.HasValue || !model.BaseCostTimingEndsTime.HasValue)
                    {
                        ModelState.AddModelError("BaseCostTimingStartsEndsHours_Empty", "Select 'Starts' and 'Ends' hours intervals");
                    }
                    else if (model.BaseCostTimingStartsDate.Value.Equals(model.BaseCostTimingEndsDate.Value) && (model.BaseCostTimingEndsTime.Value < model.BaseCostTimingStartsTime.Value))
                    {
                        ModelState.AddModelError("BaseCostTimingStartsEndsHours_EndsDateGreater", "'Ends' hours must be greater than 'Starts' hours");
                    }
                    else
                    {
                        model.BaseCostTimingStartsDate = new DateTime(
                                                  model.BaseCostTimingStartsDate.Value.Year, model.BaseCostTimingStartsDate.Value.Month, model.BaseCostTimingStartsDate.Value.Day,
                                                  model.BaseCostTimingStartsTime.Value.Hours, model.BaseCostTimingStartsTime.Value.Minutes, model.BaseCostTimingStartsTime.Value.Seconds);

                        model.BaseCostTimingEndsDate = new DateTime(
                            model.BaseCostTimingEndsDate.Value.Year, model.BaseCostTimingEndsDate.Value.Month, model.BaseCostTimingEndsDate.Value.Day,
                            model.BaseCostTimingEndsTime.Value.Hours, model.BaseCostTimingEndsTime.Value.Minutes, model.BaseCostTimingEndsTime.Value.Seconds);

                        model.BaseCostTimingScheduledAtDate = model.BaseCostTimingStartsDate.HasValue ?
                            model.BaseCostTimingStartsDate.Value : model.BaseCostTimingStartsDate;
                    }
                }

                model.BaseCostTimingScheduledAtDate = model.BaseCostTimingScheduledAtDate == null ? (DateTime?)null : model.BaseCostTimingScheduledAtDate.Value.ToUTC(business.Gmt);
                model.BaseCostTimingStartsDate = model.BaseCostTimingStartsDate == null ? (DateTime?)null : model.BaseCostTimingStartsDate.Value.ToUTC(business.Gmt);
                model.BaseCostTimingEndsDate = model.BaseCostTimingEndsDate == null ? (DateTime?)null : model.BaseCostTimingEndsDate.Value.ToUTC(business.Gmt);
                
                var result = this.repository.Promotion_UpdateTiming(User.SecurityToken.Value, model.PromotionId, model.BaseCostTimingId,
                                         model.BaseCostTimingScheduledAtDate ?? null,
                                         model.BaseCostTimingStartsDate ?? null, model.BaseCostTimingEndsDate ?? null,
                                         model.BaseCostTimingStartsDate ?? null, model.BaseCostTimingEndsDate ?? null);

                return RedirectToAction("Promotions", "BusinessProfile");
            }

            return View(model);
        }

        [HttpGet]
        public ActionResult AddBudget(int id)
        {
            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value, id);

            if (id <= 0 || promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            return View(new PromotionAddBudgetViewModel()
            {
                PromotionId = id,
                BudgetAmount = null,
                Promotion = promotion,
                RemainingTimeText = "2 days 3 hours 34 min"
            });
        }

        [HttpPost]
        public ActionResult AddBudget(PromotionAddBudgetViewModel model)
        {
            var payInfo = this.repository.Promotion_GetPayInfo_Result(User.SecurityToken.Value, model.PromotionId);
            var payResult = String.Empty;
            decimal sumPay = 0;
            decimal sumRest = 0;

            if (payInfo.IdResult != 1)
            {
                ModelState.AddModelError("GetPaymentInfoError", "Error occured during submiting promotion");
                return RedirectToAction("NewPromotionStep5");
            }

            if (payInfo.PromoRest.Value > 0 && payInfo.CampaignBudget.Value > payInfo.PromoRest.Value)
            {
                var charge = (payInfo.CampaignBudget.Value - payInfo.PromoRest.Value);
                // CALL API Payment\Pay(string cardNumber, string cardPin, DateTime cardDateExpiration, decimal amount, string description)
                payResult = this.repository.Promotion_Charge(payInfo.CreditCardNo, payInfo.CreditCardPin, payInfo.CreditCardExpDate, charge, "TEST");
                sumPay = charge;
                sumRest = payInfo.PromoRest.Value;
            }
            else if (payInfo.PromoRest.Value == 0)
            {
                var charge = payInfo.CampaignBudget.Value;
                // CALL API Payment\Pay(string cardNumber, string cardPin, DateTime cardDateExpiration, decimal amount, string description)
                payResult = this.repository.Promotion_Charge(payInfo.CreditCardNo, payInfo.CreditCardPin, payInfo.CreditCardExpDate, charge, "TEST");
                sumPay = charge;
                sumRest = 0;
            }
            else if (payInfo.PromoRest.Value >= payInfo.CampaignBudget.Value)
            {
                // DON'T CHARGE
                sumPay = 0;
                sumRest = payInfo.CampaignBudget.Value;
            }

            model.Promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value, model.PromotionId);

            if (ModelState.IsValid)
            {
                var result = this.repository.Promotion_BudgetAdd(User.SecurityToken.Value, model.PromotionId,
                    sumPay, sumRest,
                    //model.BudgetAmount.Value,
                    model.Promotion.Name, model.Promotion.PromotionText, model.Promotion.Picture, model.Promotion.PictureContentType);

                return RedirectToAction("Promotions", "BusinessProfile");
            }

            return View(model);
        }

        [HttpGet]
        public ActionResult Edit(int promotionId)
        {
            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value, promotionId);
            var perPush = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush;
            var flatFee = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().FixedCost;

            Promotion = new PromotionViewModel()
            {
                PromotionId = promotionId,
                PromotionCompaignCost = perPush,
                PromotionCompaignFlatFee = flatFee,
                CategoriesCostFlatFee = flatFee,
                CategoriesCostPerPush = perPush,
                PromotionCategories = promotion.Categories.ToList()
            };

            return RedirectToAction("PromotionCategories");
        }

        [HttpGet]
        public ActionResult Renew(int id)
        {
            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value, id);

            if (promotion.Status == PromotionStatus.Complete)
            {
                Promotion = new PromotionViewModel()
                {
                    OldPromotionId = id,
                    IsRenew = true,
                    PromotionCompaignCost = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush,
                    PromotionCategories = promotion.Categories.ToList()
                };

                return RedirectToAction("PromotionCategories");//, new { promotionId = Promotion.OldPromotionId });
            }
            else
            {
                TempData["Error"] = "To Renew promotion, it must be in status \"Completed\".";

                return RedirectToAction("Promotions", "BusinessProfile");
            }
        }

        #region Creating/Editing steps

        private PromotionViewModel Promotion
        {
            get
            {
                return (PromotionViewModel)Session["Promotion"];
            }
            set
            {
                Session["Promotion"] = value;
            }
        }

        #region Promotion Categories

        [HttpGet]
        public ActionResult PromotionCategories(int? id)
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            var model = new PromotionCategoriesViewModel()
            {
                PromotionId = Promotion.OldPromotionId,
                BaseCost = Promotion.PromotionCompaignCost,
                FlatFee = Promotion.PromotionCompaignFlatFee,
                SelectedCategories = Promotion.PromotionCategories,
                CurrentCategory = repository.Categories.FirstOrDefault(c => c.CategoryId == id),
                //Categories = (id.HasValue ? this.repository.CategoriesGetAll().Where(c => c.ParentId == id).ToList() : businessCategories),
                Categories = (id.HasValue ? this.repository.CategoriesGetAll().Where(c => c.ParentId == id).ToList()
                : this.repository.CategoriesGetAll().Where(c => !c.ParentId.HasValue).ToList()),

                SelectedCategoriesIds = Promotion.PromotionCategories.Count > 0 ?
                                        Promotion.PromotionCategories.Select(c => c.CategoryId.ToString()).Aggregate((cur, nxt) => cur + "," + nxt) : String.Empty
            };

            return View(model);
        }

        [HttpPost]
        public ActionResult PromotionCategories(string selectedCategoriesIds)
        {
            if (Promotion == null)
                return RedirectToAction("PromotionCategories", "BusinessProfile");

            if (String.IsNullOrWhiteSpace(selectedCategoriesIds))
                ModelState.AddModelError("Promotion_SelectedCategoriesIds", "Promotion's categories were not selected");

            if (ModelState.IsValid)
            {
                if (Promotion.IsRenew)
                {
                    var result = this.repository.Business_AddPromotion(User.SecurityToken.Value);

                    if (result.IdResult == 1)
                    {
                        var resultArray = result.Result.Split(';');
                        var promotionId = Int32.Parse(resultArray[0]);
                        var ratePerPush = Double.Parse(resultArray[1]);
                        var fixedCost = Double.Parse(resultArray[2]);

                        var categoryAddResult = this.repository.Business_AddPromotionCategories(User.SecurityToken.Value, promotionId, selectedCategoriesIds);

                        if (categoryAddResult.IdResult == 1)
                        {
                            Promotion.PromotionId = promotionId;
                            Promotion.PromotionCategories = null;

                            return RedirectToAction("PromotionProximity");
                        }
                        else
                        {
                            TempData["Error"] = "Error during adding promotion's categories.";
                        }
                    }
                    else if (result.IdResult == -2)
                    {
                        TempData["Error"] = "Credit card expired!";
                    }
                }
                else
                {
                    var categoryAddResult = this.repository.Business_AddPromotionCategories(User.SecurityToken.Value, Promotion.PromotionId, selectedCategoriesIds);

                    if (categoryAddResult.IdResult == 1)
                    {
                        var ids = selectedCategoriesIds.Split(',').Select(id => Int32.Parse(id)).ToList();

                        ids.ForEach(id =>
                        {
                            var category = this.repository.Categories.FirstOrDefault(c => c.CategoryId == id);

                            if (category != null && !Promotion.PromotionCategories.Select(c => c.CategoryId).Contains(category.CategoryId))
                                Promotion.PromotionCategories.Add(category);
                        });

                        return RedirectToAction("PromotionProximity");
                    }
                    else
                    {
                        TempData["Error"] = "Error during adding promotion's categories.";
                    }
                }
            }

            var baseCost = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush;

            var model = new PromotionCategoriesViewModel()
            {
                PromotionId = Promotion.PromotionId,
                BaseCost = baseCost,
                SelectedCategories = Promotion.PromotionCategories,
                CurrentCategory = repository.Categories.FirstOrDefault(c => c.CategoryId == null),
                Categories = (Promotion.PromotionId > 0 ? this.repository.CategoriesGetAll().Where(c => c.ParentId == Promotion.PromotionId).ToList()
                                : this.repository.CategoriesGetAll().Where(c => !c.ParentId.HasValue).ToList())
            };

            return View("PromotionCategories", model);
        }

        [HttpPost]
        public ActionResult PromotionCategoriesAdd(int promotionId, string selectedCategoriesIds)
        {
            if (Promotion == null)
                return RedirectToAction("PromotionCategories", "BusinessProfile");

            if (!String.IsNullOrWhiteSpace(selectedCategoriesIds))
            {
                var ids = selectedCategoriesIds.Split(',').Select(id => Int32.Parse(id)).ToList();

                ids.ForEach(id =>
                {
                    var category = this.repository.Categories.FirstOrDefault(c => c.CategoryId == id);

                    if (category != null && !Promotion.PromotionCategories.Select(c => c.CategoryId).Contains(category.CategoryId))
                    {
                        if (category.IsSingleSelection)
                            Promotion.PromotionCategories.RemoveAll(x => x.ParentId == category.ParentId);

                        Promotion.PromotionCategories.Add(category);
                    }
                });
            }

            return RedirectToAction("PromotionCategories", new { promotionId = promotionId, flag = 1 });
        }

        [HttpGet]
        public ActionResult PromotionCategoriesRemove(int id)
        {
            if (Promotion == null)
                return RedirectToAction("PromotionCategories", "BusinessProfile");

            Promotion.PromotionCategories.Remove(Promotion.PromotionCategories.FirstOrDefault(c => c.CategoryId == id));

            return RedirectToAction("PromotionCategories", new { promotionId = Promotion.PromotionId, flag = 1 });
        }

        #endregion

        #region Promotion Proximity

        [HttpGet]
        public ActionResult PromotionProximity()
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value,
                Promotion.IsRenew ? Promotion.OldPromotionId : Promotion.PromotionId);

            var feets = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "feet").OrderBy(p => p.ProximityRadiusId).ToList();
            var miles = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "miles").OrderBy(p => p.ProximityRadiusId).ToList();

            PopulateFeetsSelect(feets, promotion.ProximityRadiusId ?? 0);
            PopulateOtsideRadiuses(promotion);

            var proximityOutside = GetProximityRadiusOutside(promotion);

            return View(new PromotionProximityViewModel()
            {
                PromotionId = Promotion.PromotionId,
                PromotionCompaignFlatFee = Promotion.PromotionCompaignFlatFee,
                PromotionCompaignCost = Promotion.PromotionCompaignCost,
                ProximityFlatFee = promotion.ProximityRadius.FixedCost,
                ProximityCost = promotion.ProximityRadius.RatePerPush,
                RegisteredOutsideFixedCost = proximityOutside != null ? proximityOutside.FixedCost : 0,
                RegisteredOutsideRatePerPush = proximityOutside != null ? proximityOutside.RatePerPush : 0,
                ProximityRadiusesFeets = feets,
                ProximityRadiusesMiles = miles,
                SelectedProximityRadiusId = promotion.ProximityRadiusId,
                IsFeetsSelected = feets.Select(x => x.ProximityRadiusId).Contains(promotion.ProximityRadiusId ?? 0),
                IsRegisteredOutside = (promotion.RegisteredOutsideOfCity || promotion.RegisteredOutsideOfState || promotion.RegisteredOutsideOfZip)
            });
        }

        [HttpPost]
        public ActionResult PromotionProximity(PromotionProximityViewModel model)
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            if (!model.SelectedProximityRadiusId.HasValue || model.SelectedProximityRadiusId <= 0)
                ModelState.AddModelError("SelectedProximityRadiusId", "Proximity Radius was not selected");

            if (model.IsCustomRangeSelected && String.IsNullOrWhiteSpace(model.CustomRangeValue))
                ModelState.AddModelError("CutomRange", "Custom Range was not entered");

            var feets = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "feet").OrderBy(p => p.ProximityRadiusId).ToList();
            var miles = repository.ProximityRadiuses.Where(p => p.RadiusUnits == "miles").OrderBy(p => p.ProximityRadiusId).ToList();

            if (ModelState.IsValid)
            {
                var isRegisteredOutSideOfZIP = model.RadiusCode == "ZIP";
                var isRegisteredOutSideOfState = model.RadiusCode == "STATE";
                var isRegisteredOutSideOfCity = model.RadiusCode == "CITY";

                var result = this.repository.Promotion_ProximityRadius_Update(User.SecurityToken.Value, model.PromotionId, model.SelectedProximityRadiusId.Value,
                      (!String.IsNullOrWhiteSpace(model.CustomRangeValue)) ? (Nullable<Int32>)Int32.Parse(model.CustomRangeValue) : null,
                      model.IsOver200MilesSelected,
                      (model.IsRegisteredOutside ? (isRegisteredOutSideOfZIP) : false),
                      (model.IsRegisteredOutside ? (isRegisteredOutSideOfState) : false),
                      (model.IsRegisteredOutside ? (isRegisteredOutSideOfCity) : false));

                var radius = this.repository.ProximityRadiuses.SingleOrDefault(x => x.ProximityRadiusId == model.SelectedProximityRadiusId);

                Promotion.PromotionCompaignCost = model.PromotionCompaignCost + radius.RatePerPush;
                Promotion.PromotionCompaignFlatFee = model.PromotionCompaignFlatFee + radius.FixedCost;

                Promotion.SelectedRadiusText = String.Format("{1} {0}", (model.IsFeetsSelected ? "feets" : "miles"),
                    (model.IsFeetsSelected ? feets.FirstOrDefault(x => x.ProximityRadiusId == model.SelectedProximityRadiusId).ToRadius.ToString() :
                    (model.IsCustomRangeSelected ? model.CustomRangeValue :
                    (model.IsOver200MilesSelected ? "Over 200" : miles.FirstOrDefault(x => x.ProximityRadiusId == model.SelectedProximityRadiusId).ToRadius.ToString()))));

                return RedirectToAction("PromotionTiming");
            }

            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value,
                Promotion.IsRenew ? Promotion.OldPromotionId : Promotion.PromotionId);

            PopulateFeetsSelect(feets, promotion.ProximityRadiusId ?? 0);
            PopulateOtsideRadiuses(promotion);

            return View(new PromotionProximityViewModel()
            {
                PromotionId = model.PromotionId,
                ProximityRadiusesFeets = feets,
                ProximityRadiusesMiles = miles
            });
        }

        #endregion

        #region Promotion Timing

        [HttpGet]
        public ActionResult PromotionTiming()
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value,
                Promotion.IsRenew ? Promotion.OldPromotionId : Promotion.PromotionId);
            var baseCostsTiming = this.repository.BaseCostTimings.ToList();

            var model = new PromotionTimingViewModel()
            {
                PromotionId = Promotion.PromotionId,
                BaseCostTimingId = promotion.BaseCostTimingId ?? 0,//PromotionConstants.TIMING_INSTANT_NOW,
                PromotionCompaignFlatFee = Promotion.PromotionCompaignFlatFee,
                PromotionCompaignCost = Promotion.PromotionCompaignCost,

                BaseCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush,
                InstantNowCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW).FirstOrDefault().RatePerPush,
                InstantNowFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW).FirstOrDefault().FixedCost,
                ScheduledAtCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT).FirstOrDefault().RatePerPush,
                ScheduledAtFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT).FirstOrDefault().FixedCost,
                DateRangeWithTimeIntervalCost = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE).FirstOrDefault().RatePerPush,
                DateRangeWithTimeIntervalFlatFee = baseCostsTiming.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE).FirstOrDefault().FixedCost,

                TimingFlatFee = baseCostsTiming.SingleOrDefault(x => x.BaseCostTimingId == promotion.BaseCostTimingId).FixedCost,
                TimingCost = baseCostsTiming.SingleOrDefault(x => x.BaseCostTimingId == promotion.BaseCostTimingId).RatePerPush,

                BaseCostTimingScheduledAtDate = promotion.BaseCostTimingScheduledAt ?? null,
                BaseCostTimingScheduledAtTime = promotion.BaseCostTimingScheduledAt.HasValue ? promotion.BaseCostTimingScheduledAt.Value.TimeOfDay : new Nullable<TimeSpan>(),
                BaseCostTimingStartsDate = promotion.BaseCostTimingStarts ?? null,
                BaseCostTimingStartsTime = promotion.BaseCostTimingStarts.HasValue ? promotion.BaseCostTimingStarts.Value.TimeOfDay : new Nullable<TimeSpan>(),
                BaseCostTimingEndsDate = promotion.BaseCostTimingEnds ?? null,
                BaseCostTimingEndsTime = promotion.BaseCostTimingEnds.HasValue ? promotion.BaseCostTimingEnds.Value.TimeOfDay : new Nullable<TimeSpan>()
            };

            if (Promotion.IsRenew)
            {
                model.BaseCostTimingScheduledAtDate = null;
                model.BaseCostTimingScheduledAtTime = new Nullable<TimeSpan>();
                model.BaseCostTimingStartsDate = null;
                model.BaseCostTimingStartsTime = new Nullable<TimeSpan>();
                model.BaseCostTimingEndsDate = null;
                model.BaseCostTimingEndsTime = new Nullable<TimeSpan>();
            }

            return View(model);
        }

        [HttpPost]
        public ActionResult PromotionTiming(PromotionTimingViewModel model)
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            if (model.BaseCostTimingId <= 0)
                ModelState.AddModelError("SelectedBaseCostTimingId", "Campaign Timing was not selected");

            if (ModelState.IsValid)
            {
                var business = repository.BusinessGetByToken(User.SecurityToken.Value);

                if (model.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT)
                {
                    if (!model.BaseCostTimingScheduledAtDate.HasValue)
                    {
                        ModelState.AddModelError("BaseCostTimingScheduledAt_EmptyDate", "Select 'Scheduled at' date");
                    }
                    else
                    {
                        model.BaseCostTimingScheduledAtDate = new DateTime(
                            model.BaseCostTimingScheduledAtDate.Value.Year, model.BaseCostTimingScheduledAtDate.Value.Month, model.BaseCostTimingScheduledAtDate.Value.Day,
                            model.BaseCostTimingScheduledAtTime.Value.Hours, model.BaseCostTimingScheduledAtTime.Value.Minutes, model.BaseCostTimingScheduledAtTime.Value.Seconds);
                    }
                }
                else if (model.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE)
                {
                    if (!model.BaseCostTimingStartsDate.HasValue || !model.BaseCostTimingEndsDate.HasValue)
                    {
                        ModelState.AddModelError("BaseCostTimingStartsEndsDates_Empty", "Select 'Start Date' and 'End Date' intervals");
                    }
                    else if (model.BaseCostTimingStartsDate.Value > model.BaseCostTimingEndsDate.Value)
                    {
                        ModelState.AddModelError("BaseCostTimingStartsEndsDates_EndsDateGreater", "'End Date' must be greater than 'Start Date'");
                    }
                    else if (!model.BaseCostTimingStartsTime.HasValue || !model.BaseCostTimingEndsTime.HasValue)
                    {
                        ModelState.AddModelError("BaseCostTimingStartsEndsHours_Empty", "Select 'Starts' and 'Ends' hours intervals");
                    }
                    else if (model.BaseCostTimingStartsDate.Value.Equals(model.BaseCostTimingEndsDate.Value) && (model.BaseCostTimingEndsTime.Value < model.BaseCostTimingStartsTime.Value))
                    {
                        ModelState.AddModelError("BaseCostTimingStartsEndsHours_EndsDateGreater", "'Ends' hours must be greater than 'Starts' hours");
                    }
                    else
                    {
                        model.BaseCostTimingStartsDate = new DateTime(
                            model.BaseCostTimingStartsDate.Value.Year, model.BaseCostTimingStartsDate.Value.Month, model.BaseCostTimingStartsDate.Value.Day,
                            model.BaseCostTimingStartsTime.Value.Hours, model.BaseCostTimingStartsTime.Value.Minutes, model.BaseCostTimingStartsTime.Value.Seconds);

                        model.BaseCostTimingEndsDate = new DateTime(
                            model.BaseCostTimingEndsDate.Value.Year, model.BaseCostTimingEndsDate.Value.Month, model.BaseCostTimingEndsDate.Value.Day,
                            model.BaseCostTimingEndsTime.Value.Hours, model.BaseCostTimingEndsTime.Value.Minutes, model.BaseCostTimingEndsTime.Value.Seconds);

                        model.BaseCostTimingScheduledAtDate = model.BaseCostTimingStartsDate.HasValue ?
                        model.BaseCostTimingStartsDate.Value : model.BaseCostTimingStartsDate;
                    }
                }

                if (!ModelState.IsValid)
                {
                    model.PromotionCompaignCost = (model.PromotionCompaignCost - model.TimingCost);
                    model.PromotionCompaignFlatFee = (model.PromotionCompaignFlatFee - model.TimingFlatFee);

                    return View(model);
                }

                Promotion.PromotionCompaignCost = (model.PromotionCompaignCost + model.TimingCost);
                Promotion.PromotionCompaignFlatFee = (model.PromotionCompaignFlatFee + model.TimingFlatFee);

                Promotion.TimingCostFlatFee = model.TimingFlatFee;
                Promotion.TimingCostPerPush = model.TimingCost;

                Promotion.SelectedTimingText = String.Format("{0}",
                    (model.BaseCostTimingId == PromotionConstants.TIMING_INSTANT_NOW ? "Instant now" :
                    (model.BaseCostTimingId == PromotionConstants.TIMING_SCHEDULED_AT ? "Scheduled at " + model.BaseCostTimingScheduledAtDate.Value.ToString("MM/dd/yy") :
                    model.BaseCostTimingId == PromotionConstants.TIMING_ONGOING_WITH_DATE_RANGE ?
                    String.Format("Date range with time interval from {0} to {1}",
                                    model.BaseCostTimingStartsDate.Value.ToString("MM/dd/yy hh:mm tt"),
                                    model.BaseCostTimingEndsDate.Value.ToString("MM/dd/yy hh:mm tt")) : String.Empty)));
                

                model.BaseCostTimingScheduledAtDate = model.BaseCostTimingScheduledAtDate == null ? (DateTime?)null : model.BaseCostTimingScheduledAtDate.Value.ToUTC(business.Gmt);
                model.BaseCostTimingStartsDate = model.BaseCostTimingStartsDate == null ? (DateTime?)null : model.BaseCostTimingStartsDate.Value.ToUTC(business.Gmt);
                model.BaseCostTimingEndsDate = model.BaseCostTimingEndsDate == null ? (DateTime?)null : model.BaseCostTimingEndsDate.Value.ToUTC(business.Gmt);

                var result = this.repository.Promotion_BaseCostTiming_Update(User.SecurityToken.Value, model.PromotionId, model.BaseCostTimingId,
                                         model.BaseCostTimingScheduledAtDate ?? model.ClientDateTime.ToUTC(business.Gmt),
                                         model.BaseCostTimingStartsDate ?? null, model.BaseCostTimingEndsDate ?? null,
                                         model.BaseCostTimingStartsDate ?? null, model.BaseCostTimingEndsDate ?? null);

                return RedirectToAction("PromotionBudgetSelection");
            }

            return View(model);
        }

        #endregion

        #region Promotion Budget Selection

        [HttpGet]
        public ActionResult PromotionBudgetSelection()
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value,
                Promotion.IsRenew ? Promotion.OldPromotionId : Promotion.PromotionId);

            var promoImage = this.repository.PromotionGetById(Promotion.IsRenew ? Promotion.OldPromotionId : Promotion.PromotionId);

            return View(new PromotionBudgetSelectionViewModel()
            {
                Renew = Promotion.IsRenew,
                PromotionId = Promotion.PromotionId,
                OldPromotionId = Promotion.OldPromotionId,
                BudgetAmount = promotion.CampaignBudget,
                PromotionName = promotion.Name,
                PromotionText = promotion.PromotionText,
                TimingCost = Promotion.TimingCostPerPush,
                PromotionCompaignCost = Promotion.PromotionCompaignCost,
                PromotionCompaignFlatFee = Promotion.PromotionCompaignFlatFee,
                Picture = promoImage.Picture,
                PictureContentType = promoImage.PictureContentType
            });
        }

        [HttpPost]
        public ActionResult PromotionBudgetSelection(PromotionBudgetSelectionViewModel model, string imagePath)
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            if (this.ModelState.IsValid)
            {
                if (!String.IsNullOrWhiteSpace(imagePath))
                {
                    /*var filePath = Server.MapPath(imagePath);
                    var fileInfo = new System.IO.FileInfo(filePath);

                    using (var fsStream = System.IO.File.OpenRead(filePath))
                    {
                        model.Picture = new byte[fsStream.Length];
                        model.PictureContentType = "image/" + fileInfo.Extension.Replace(".", String.Empty);
                        fsStream.Read(model.Picture, 0, (int)fsStream.Length);
                    }*/

                    if ((this.UploadedTempImageBytes != null && this.UploadedTempImageBytes.Length > 0) && !String.IsNullOrEmpty(this.UploadedTempImageMimeType))
                    {
                        model.Picture = this.UploadedTempImageBytes;
                        model.PictureContentType = this.UploadedTempImageMimeType;
                    }
                }
                else
                {
                    var promo = this.repository.PromotionGetById(Promotion.IsRenew ? Promotion.OldPromotionId : Promotion.PromotionId);
                    //PromotionGetByTokenAndId(User.SecurityToken.Value, (Promotion.IsRenew ? Promotion.OldPromotionId : Promotion.PromotionId));

                    model.Picture = promo.Picture;
                    model.PictureContentType = promo.PictureContentType;
                }

                var result = this.repository.Promotion_UpdateBudget(User.SecurityToken.Value, model.PromotionId, model.BudgetAmount.Value,
                    model.PromotionName, model.PromotionText, model.Picture, model.PictureContentType, null, null);

                if (result == 1)
                {
                    Promotion.Budget = model.BudgetAmount ?? 0;
                    Promotion.Name = model.PromotionName;
                    Promotion.Text = model.PromotionText;

                    return RedirectToAction("PromotionReview");
                }
            }

            return View(model);
        }

        public ActionResult PromoImageUploadControl(int? id)
        {
            return PartialView("_ImageUploadControl", id);
        }

        #endregion

        #region Promotion Review

        [HttpGet]
        public ActionResult PromotionReview()
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            var promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value,
                Promotion.IsRenew ? Promotion.OldPromotionId : Promotion.PromotionId);

            return View(new PromotionReviewViewModel()
            {
                PromotionId = Promotion.PromotionId,
                Promotion = this.repository.PromotionGetByTokenAndId(User.SecurityToken.Value, Promotion.PromotionId),
                SelectedRadiusText = Promotion.SelectedRadiusText,
                SelectedTimingText = Promotion.SelectedTimingText,
                Budget = Promotion.Budget ?? 0,
                MaxPushes = promotion.MaxPushes ?? 0,
                Name = Promotion.Name,
                Text = Promotion.Text
            });
        }

        //[HttpGet]
        public ActionResult PromotionSubmit()
        {
            if (Promotion == null)
                return RedirectToAction("Promotions", "BusinessProfile");

            //var result = this.repository.Promotion_Submit(User.SecurityToken.Value, Promotion.PromotionId);

            // START NEW LOGIC
            var payInfo = this.repository.Promotion_GetPayInfo_Result(User.SecurityToken.Value, Promotion.PromotionId);
            var payResult = String.Empty;
            decimal sumPay = 0;
            decimal sumRest = 0;

            if (payInfo.IdResult != 1)
            {
                //ModelState.AddModelError("GetPaymentInfoError", "Error occured during submiting promotion");
                TempData["PaymentError"] = "Error occured during submiting promotion";
                return RedirectToAction("NewPromotionStep5");
            }

            //if (!payInfo.CampaignBudget.HasValue)
            //    payInfo.CampaignBudget = 0;

            if (payInfo.PromoRest.Value > 0 && payInfo.CampaignBudget.Value > payInfo.PromoRest.Value)
            {
                var charge = (payInfo.CampaignBudget.Value - payInfo.PromoRest.Value);

                // CALL API Payment\Pay(string cardNumber, string cardPin, DateTime cardDateExpiration, decimal amount, string description)
                payResult = this.repository.Promotion_Charge(payInfo.CreditCardNo, payInfo.CreditCardPin, payInfo.CreditCardExpDate, charge, "TEST");
                sumPay = charge;
                sumRest = payInfo.PromoRest.Value;
            }
            else if (payInfo.PromoRest.Value == 0)
            {
                var charge = payInfo.CampaignBudget.Value;

                // CALL API Payment\Pay(string cardNumber, string cardPin, DateTime cardDateExpiration, decimal amount, string description)
                payResult = this.repository.Promotion_Charge(payInfo.CreditCardNo, payInfo.CreditCardPin, payInfo.CreditCardExpDate, charge, "TEST");
                sumPay = charge;
                sumRest = 0;
            }
            else if (payInfo.PromoRest.Value > payInfo.CampaignBudget.Value)
            {
                // DON'T CHARGE
                sumPay = 0;
                sumRest = payInfo.CampaignBudget.Value;
            }

            if (!String.IsNullOrWhiteSpace(payResult))
            {
                //ModelState.AddModelError("PaymentError", payResult);
                TempData["PaymentError"] = payResult;
                return RedirectToAction("PromotionReview");
            }

            var result = this.repository.Promotion_Submit(User.SecurityToken.Value, Promotion.PromotionId, sumPay, sumRest);
            // END NEW

            Promotion = null;

            return RedirectToAction("Promotions", "BusinessProfile");
        }

        #endregion

        #endregion

        #region Methods

        public FileContentResult GetPromotionPicture(int id, int w, int h)
        {
            var promotion = this.repository.PromotionGetById(id);

            if (promotion != null && promotion.Picture != null)
            {
                var newSizedImg = Helper.ScaleImage(promotion.Picture, w, h);
                byte[] newSizedImgBytes = Helper.ImageToByteArray(newSizedImg);

                return File(newSizedImgBytes, promotion.PictureContentType);
            }
            else
            {
                var newSizedImg = Helper.ScaleImage(System.IO.File.ReadAllBytes(Server.MapPath("~/Content/zatify/images/no_image.jpg")), w, h);
                byte[] newSizedImgBytes = Helper.ImageToByteArray(newSizedImg);

                return File(newSizedImgBytes, "image/jpeg");
            }
        }

        private void PopulateFeetsSelect(List<ProximityRadius> feets, int proximityRadiusId)
        {
            var feetsSelectList = new List<SelectListItem>();

            feets.ForEach(f =>
            {
                feetsSelectList.Add(new SelectListItem()
                {
                    Text = f.ToRadius.ToString(),
                    Value = f.ProximityRadiusId.ToString() + ";" + f.RatePerPush.ToString("0.00"),
                    Selected = (f.ProximityRadiusId == proximityRadiusId)
                });
            });

            ViewData["ProximityFeets"] = feetsSelectList;
        }

        private void PopulateOtsideRadiuses(Promotion promo)
        {
            var outsideRadiusesSelectList = new List<SelectListItem>();

            var code = promo.RegisteredOutsideOfCity ? "CITY" :
                promo.RegisteredOutsideOfState ? "STATE" :
                promo.RegisteredOutsideOfZip ? "ZIP" : String.Empty;

            this.repository.ProximityRadiusesOutside.ToList().ForEach(r =>
            {
                outsideRadiusesSelectList.Add(new SelectListItem()
                {
                    Text = r.Description,
                    Value = r.ProximityRadiusOutsideCode + ";" + r.FixedCost.ToString("0.00") + ";" + r.RatePerPush.ToString("0.00"),
                    Selected = (r.ProximityRadiusOutsideCode == code)
                });
            });

            ViewData["OutsideRadiuses"] = outsideRadiusesSelectList;
        }

        private ProximityRadiusOutside GetProximityRadiusOutside(Promotion promo)
        {
            var code = promo.RegisteredOutsideOfCity ? "CITY" :
                           promo.RegisteredOutsideOfState ? "STATE" :
                           promo.RegisteredOutsideOfZip ? "ZIP" : String.Empty;

            return this.repository.ProximityRadiusesOutside.SingleOrDefault(x => String.Equals(x.ProximityRadiusOutsideCode, code));
        }

        private decimal GetPromotionCompaignPerPush(Promotion promo)
        {
            var basePerPush = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().RatePerPush;
            var radiusPerPush = this.repository.ProximityRadiuses.SingleOrDefault(x => x.ProximityRadiusId == promo.ProximityRadiusId).RatePerPush;
            var baseCostTimingPerPush = this.repository.BaseCostTimings.FirstOrDefault(x => x.BaseCostTimingId == promo.BaseCostTimingId).RatePerPush;

            return (basePerPush + radiusPerPush + baseCostTimingPerPush);
        }

        private decimal GetPromotionCompaignFixedCost(Promotion promo)
        {
            var baseFixedCost = this.repository.BaseCostTimings.Where(x => x.BaseCostTimingId == PromotionConstants.TIMING_BASE_COST).FirstOrDefault().FixedCost;
            var radiusFixedCost = this.repository.ProximityRadiuses.SingleOrDefault(x => x.ProximityRadiusId == promo.ProximityRadiusId).FixedCost;
            var baseCostTimingFixedCost = this.repository.BaseCostTimings.FirstOrDefault(x => x.BaseCostTimingId == promo.BaseCostTimingId).FixedCost;

            return (baseFixedCost + radiusFixedCost + baseCostTimingFixedCost);
        }

        #endregion
    }
}
